package org.geektimes.projects.user.service.impl;

import org.geektimes.projects.user.db.LocalTransactional;
import org.geektimes.projects.user.domain.User;
import org.geektimes.projects.user.repository.UserRepository;
import org.geektimes.projects.user.service.UserService;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;


/**
 * @Author: jipeng
 * @Description:
 * @Date: Created in 2021/3/1 22:01
 */
public class UserServiceImpl implements UserService {
    private final Logger logger = Logger.getLogger(getClass().getName());

    @Resource(name = "bean/EntityManager")
    private EntityManager entityManager;

    @Resource(name = "bean/DatabaseUserRepository")
    private UserRepository userRepository;


    @Override
    @LocalTransactional
    public boolean register(User user) {
        EntityTransaction entityTransaction = entityManager.getTransaction();


        entityTransaction.begin();
        //defore process

        //主调用
        entityManager.persist(user);

        //调用其他方法
//        update(user);//涉及事务
        // register 方法和  update 方法存在同一线程
        // register 方法属于 Outer （外部） 事务
        // update 方法属于 Inner （内部）事务

        // Case 1:两个方法均涉及事务（并且传播行为和隔离级别相同）
        // 两者共享一个物理事务，但存在两个逻辑事务
        // 利用 ThreadLocal 管理一个物理事务（Connection）

        // rollback 情况 1： update 方法（Inner 事务），它无法主动调用 rollback 方法
        // 设置rollback only 状态， Inner TX(rollback only),说明 update 方法可能存在执行异常或者触发了数据库约束
        // 当 Outer TX 接受到 Inter TX 状态，它来执行 rollback
        // A ->  B  ->  C  ->  D  ->  E  方法调用链
        // A（B,C,D,E）内联这些方法，合成大方法
        // 关于物理事务是哪个创建的
        // 其他调用链路事务传播行为一致时，都是逻辑事务


        // Case 2:register 方法是  REQUIRED(事务创建者)， update 方法是  REQUIRES_NEW
        // 这种情况 update 方法也是 事务创建者
        // update 方法rollback-only 状态不会影响 Outer TX, Outer TX 和 Inner TX 是两个物理事务


        // Case 3:register 方法是  REQUIRED(事务创建者)， update 方法是  NESTED
        // 这种情况 update 方法同样共享了 register 方法物理事务，并且通过 Savepoint 来实现局部提交和回滚

        try {
            //after process
            entityTransaction.commit();
        } catch (Exception e) {
            logger.log(Level.SEVERE, "操作失败，回滚", e);
            entityTransaction.rollback();
            return false;
        }
        return true;
    }

    @Override
    public boolean deregister(User user) {
        return false;
    }

    @Override
    public boolean update(User user) {
        return false;
    }

    @Override
    public User queryUserById(Long id) {
        return null;
    }

    @Override
    public User queryUserByNameAndPassword(String name, String password) {
        return null;
    }

    @Override
    public Collection<User> findAll() {
        return userRepository.getAll();
    }


}
